package com.endbd.gateway.globalfilter;

import com.endbd.feignapi.api.SystemApi;
import com.endbd.feignapi.model.system.Module;
import com.endbd.feignapi.model.system.User;
import com.endbd.feignapi.util.LoginToken;
import com.endbd.feignapi.util.ResultBody;
import com.endbd.feignapi.util.ResultMessage;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.reactivestreams.Publisher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

@Component
public class logWrite implements GlobalFilter, Ordered {

    @Autowired
    private SystemApi systemApi;

    @Autowired
    private RedisTemplate redisTemplate;

    ExecutorService executorService = Executors.newFixedThreadPool(1);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        String uri = exchange.getRequest().getURI().toString();
        //判断是否为登录或登出请求
        if (uri.contains("/system/permission/login")
                || uri.contains("/system/permission/logout")
                || uri.contains("/system/permission/uIdCheck")) {
            //直接放行
            return chain.filter(exchange);
        }

        HttpHeaders headers = exchange.getRequest().getHeaders();
        List<String> locationList = headers.get("location");
        List<String> uIdList = headers.get("uId");
        String location;
        assert uIdList != null;
        String uId = uIdList.get(0);
        Integer moduleId = null;

        Map<String, LoginToken> loginToken = (Map<String, LoginToken>) redisTemplate.opsForValue().get("loginToken");
        assert loginToken != null;
        LoginToken token = loginToken.get(uId);

        //判断操作的模块moduleId
        if (locationList != null) {
            location = locationList.get(0);
            location = location.substring(location.indexOf("/html/")+6);
            if (location.lastIndexOf("/") != -1)
                location = location.substring(0, location.lastIndexOf("/"));

//            Map<String, List<List<Module>>> loginModule = (Map<String, List<List<Module>>>) redisTemplate.opsForValue().get("loginModule");
//            if (loginModule == null) loginModule = new HashMap<>();

            List<List<Module>> lists = token.getModules();

            if (lists == null) {
                exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);//没有获取到模块，不允许操作
                return exchange.getResponse().setComplete();
            } else {
                exit:
                for (List<Module> list : lists) {
                    for (Module module : list) {
                        if (module.getModuleMUrl()!=null && module.getModuleMUrl().contains(location)) {
                            moduleId = module.getModuleId();
                            break exit;
                        }
                    }
                }
            }
        } else {
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);//没有获取到模块，不允许操作
            return exchange.getResponse().setComplete();
        }

        Integer finalModuleId = moduleId;

        if (finalModuleId != null) {
            ServerHttpResponse response = exchange.getResponse();
            DataBufferFactory bufferFactory = response.bufferFactory();
            ServerHttpResponseDecorator serverHttpResponseDecorator = new ServerHttpResponseDecorator(response) {
                @Override
                public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                    if (getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) {
                        Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                        return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
                            DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                            DataBuffer join = dataBufferFactory.join(dataBuffers);
                            byte[] content = new byte[join.readableByteCount()];
                            join.read(content);
                            DataBufferUtils.release(join);
                            // 流转为字符串
                            String responseData = new String(content, StandardCharsets.UTF_8);

                            String logMessage;
                            ObjectMapper om = new ObjectMapper();
                            try { //尝试把JSON转为resultMessage
                                ResultMessage resultMessage = om.readValue(responseData, ResultMessage.class);
                                logMessage = resultMessage.getMsg();
                            } catch (JsonProcessingException e) { // 获得的JSON不是resultMessage
                                try { //尝试把JSON转为resultBody
                                    ResultBody resultBody = om.readValue(responseData, ResultBody.class);
                                    logMessage = resultBody.getMessage();
                                } catch (JsonProcessingException ex) {
                                    return bufferFactory.wrap(content);
                                }
                            }

                            String finalLogMessage = logMessage;

                            if (finalLogMessage != null && !"".equals(finalLogMessage) && !"null".equals(finalLogMessage) && !"success".equals(finalLogMessage) && !finalLogMessage.contains("查询")) {
                                //调用log接口打印log
                                Future<Boolean> future = executorService.submit(() -> systemApi.recordLog(Integer.valueOf(uId), finalModuleId, finalLogMessage));
                                try {
                                    Boolean aBoolean = future.get();
                                } catch (InterruptedException | ExecutionException e) {
                                    e.printStackTrace();
                                }
                            }

                            return bufferFactory.wrap(content);
                        }));
                    }
                    return super.writeWith(body);
                }
            };
            return chain.filter(exchange.mutate().response(serverHttpResponseDecorator).build());
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1;
    }
}
